﻿/*----------------------------------------------------------------------------------------
*
*  Copyright 2019, Gao Hai Hui, <fromzeropoint@126.com>.  All rights reserved.
*  https://gitee.com/helloworldghh/xoskit.git
*  Use of this source code is governed by a MIT license
*  that can be found in the License file.
*
----------------------------------------------------------------------------------------*/
#include "../import/head.h"
#include "../global/head.h"
#include "node_impl.h"
#include "doc_impl.h"
#include "xml_impl.h"

namespace xos_xml
{
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    xml_impl::xml_impl()
    {
        init_data();
    }

    xml_impl::~xml_impl()
    {
        if( g_pSysData )
        {
            g_pSysData->term();
            delete g_pSysData;
            g_pSysData = 0;
        }
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    int xml_impl::route_path( xos_xml::i_xml_node * pXmlNode, xos_box::i_variant * pParentNode, xos_box::i_variant ** ppCurNode )
    {
        int ret = 0;

        xos_box::i_variant * pCurNode = 0;
        xos_xml::i_xml_node * pChild = 0;
        bool bIsProperty = false;
        bool bIsList = false;

        {
            pCurNode = g_pSysData->m_pContainer->vt();
            pXmlNode->get_child_node( &pChild );
            bIsProperty = is_property( pXmlNode );
            bIsList = is_list( pXmlNode );
        }

        if( pChild || bIsList || bIsProperty )
        {
            if( bIsList )
            {
                xos_box::i_list * pList = g_pSysData->m_pContainer->list();
                pCurNode->set_list( pList, true );
            }
            else
            {
                xos_box::i_property * pProperty = g_pSysData->m_pContainer->prop();
                pCurNode->set_prop( pProperty, true );
            }
            if( m_pfNode )
            {
                char name[1024] = { 0 };
                pChild->get_node_name( name, sizeof( name ), 0 );
                m_pfNode( name );
            }
        }
        else
        {
            char value[4096] = { 0 };
            char name[1024] = { 0 };
            pXmlNode->get_node_value( value, sizeof( value ), 0 );
            pXmlNode->get_node_name( name, sizeof( name ), 0 );
            pCurNode->set( value );
            if( m_pfValue )
            {
                m_pfValue( name, value );
            }
        }
        // 读取节点属性
        if( 0 == pXmlNode->reset_property() )
        {
            xos_box::i_property * pProperty = g_pSysData->m_pContainer->prop();
            pCurNode->set_attr( pProperty );
            int r = 0;
            while( 0 == r )
            {
                char value[4096] = { 0 };
                char name[1024] = { 0 };
                pXmlNode->get_node_prop( name, sizeof( name ), 0, value, sizeof( value ), 0 );
                r = pXmlNode->next_property();
                pProperty->set( name, value );
            }
        }

        while( pChild )
        {
            route_path( pChild, pCurNode, 0 );
            xos_xml::i_xml_node * pT = pChild;
            pChild = 0;
            pT->get_next_sibling_node( &pChild );
            xos_stl::release_interface( pT );
        }

        // add to parent
        if( pParentNode )
        {
            xos_box::i_variant::VT_TYPE type = pParentNode->get_type( 0 );
            if( xos_box::i_variant::VT_LIST == type )
            {
                pParentNode->list( 0 )->push_back( pCurNode );
            }
            else
            {
                char name[1024] = { 0 };
                pXmlNode->get_node_name( name, sizeof( name ), 0 );
                pParentNode->prop( 0 )->set( name, pCurNode );
            }
            pCurNode = 0;
        }

        if( pCurNode && ppCurNode )
        {
            *ppCurNode = pCurNode;
            pCurNode = 0;
        }

        xos_stl::release_interface( pCurNode );
        xos_stl::release_interface( pChild );

        return ret;
    }

    bool xml_impl::is_property( xos_xml::i_xml_node * pXmlNode )
    {
        bool bRet = false;

        {
            char type[256] = { 0 };
            pXmlNode->get_node_prop( "type", type, sizeof( type ), 0 );
            if( 0 == g_pSysData->m_pContainer->crt()->strcmp( type, "property" ) )
            {
                bRet = true;
            }
        }

        return bRet;
    }

    bool xml_impl::is_list( xos_xml::i_xml_node * pXmlNode )
    {
        typedef std::map< std::string, int > NAME_MAP;
        typedef NAME_MAP::iterator NAME_ITER;
        bool bRet = false;

        if( !bRet )
        {
            char type[256] = { 0 };
            pXmlNode->get_node_prop( "type", type, sizeof( type ), 0 );
            if( 0 == g_pSysData->m_pContainer->crt()->strcmp( type, "list" ) )
            {
                bRet = true;
            }
        }

        if( !bRet )
        {
            xos_xml::i_xml_node * pChild = 0;
            NAME_MAP names;
            pXmlNode->get_child_node( &pChild );
            while( pChild )
            {
                char name[1024] = { 0 };
                pChild->get_node_name( name, sizeof( name ), 0 );
                NAME_ITER iter = names.find( name );
                if( iter != names.end() )
                {
                    pChild->release();
                    pChild = 0;
                    bRet = true;
                    break;
                }
                else
                {
                    names[name] = 0;
                }
                xos_xml::i_xml_node * pT = pChild;
                pChild = 0;
                pT->get_next_sibling_node( &pChild );
                pT->release();
                pT = 0;
            }
        }

        return bRet;
    }

    int xml_impl::init_data()
    {
        int ret = 0;

        m_pfValue = 0;
        m_pfNode = 0;

        return ret;
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    // 
    // load and parse xml to xos_box::i_property.
    // 
    // xml item property : type = "list" 表示下边是列表,xos_box::i_list保存载入的数据
    // 没有属性时，默认为 type = "map"
    // 
    int xml_impl::load_xml( const char * lpszFile, f_node lpfNode, f_value lpfValue, xos_box::i_variant ** ppvt, xos_box::i_property ** ppv )
    {
        int ret = 0;

        xos_box::i_variant * pRootNode = 0;
        xos_xml::i_xml_node * pRoot = 0;
        xos_xml::i_xml_doc * pDoc = 0;

        if( 0 == ret )
        {
            m_pfValue = lpfValue;
            m_pfNode = lpfNode;
        }

        if( 0 == ret )
        {
            ret = create_doc( &pDoc );
        }

        if( 0 == ret )
        {
            ret = pDoc->load_xml_file( lpszFile );
        }

        if( 0 == ret )
        {
            ret = pDoc->get_root_node( &pRoot );
        }

        if( 0 == ret )
        {
            ret = route_path( pRoot, 0, &pRootNode );
        }

        if( ( 0 == ret ) && ppv )
        {
            *ppv = pRootNode->prop( 0 );
            pRootNode->set( 0 );
        }

        if( ( 0 == ret ) && ppvt )
        {
            *ppvt = pRootNode;
            pRootNode = 0;
        }

        xos_stl::release_interface( pRootNode );
        xos_stl::release_interface( pRoot );
        xos_stl::release_interface( pDoc );
        m_pfValue = 0;
        m_pfNode = 0;

        return ret;
    }

    // 
    // create node
    // 
    int xml_impl::create_node( i_xml_node ** ppv )
    {
        int nRet = 0;

        node_impl::T * p = node_impl::get_item_from_pool( true );
        p->init();
        *ppv = p;

        return nRet;
    }

    // 
    // create doc
    // 
    int xml_impl::create_doc( i_xml_doc ** ppv )
    {
        int nRet = 0;

        doc_impl::T * p = doc_impl::get_item_from_pool( true );
        p->init();
        *ppv = p;

        return nRet;
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    int xml_impl::put_back_to_pool( T * pT, bool bLock )
    {
        int ret = 0;
        delete this;
        return ret;
    }

    int xml_impl::init()
    {
        int ret = 0;
        return ret;
    }

    int xml_impl::term()
    {
        int ret = 0;
        init_data();
        return ret;
    }

} // xos_xml
